package org.tgcms.core.dal.appengine.dao;

import java.util.List;

import javax.jdo.PersistenceManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tgcms.core.dal.appengine.domain.AppengineEntityBase;
import org.tgcms.core.dal.appengine.domain.AppengineEntity;
import org.tgcms.core.dal.appengine.domain.AppengineWebsite;
import org.tgcms.core.dal.dao.DaoException;
import org.tgcms.core.dal.dao.EntityDao;
import org.tgcms.core.dal.dto.Website;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Transaction;

@SuppressWarnings("unchecked")
public abstract class AppengineEntityDao<T extends AppengineEntity, I, P> implements EntityDao<I, P> {

	Logger logger = LoggerFactory.getLogger(AppengineEntityDao.class);
	DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		
	private final Class<T> entityClass;
	private final Class<I> entityInterface;

	public AppengineEntityDao(Class<T> entityClass, Class<I> entityInterface) {
		this.entityClass = entityClass;
		this.entityInterface = entityInterface;
	}

	@Override
	public List<I> listAll() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.getFetchPlan().addGroup("all");
		List<I> list = (List<I>) pm.newQuery(entityClass).execute();
		list = (List<I>) pm.detachCopyAll(list);
		pm.close();
		return list;
	}

	@Override
	public I get(Long id) throws DaoException {
//		Website website = new AppengineWebsiteDao().getDefaultWebsite();
//		Key key = KeyFactory.createKey(website.getKey(), clazz.getSimpleName(), id);
//
//		PersistenceManager pm = PMF.get().getPersistenceManager();
//		pm.getFetchPlan().addGroup("all");
//		pm.setDetachAllOnCommit(true);
//
//		T entity = null;
//		try {
//			entity = pm.getObjectById(clazz, key);
//			entity = pm.detachCopy(entity);
//		} catch (Exception e) {
//			logger.error(
//					"Entity " + clazz.getSimpleName() + " with id" + id + ", key " + key
//							+ " not fount on the website " + website.getName() + ", id: "
//							+ website.getId(), e);
//		} finally {
//			pm.close();
//		}
//		return entity;
		return null;
	}

	@Override
	public I put(I object) throws DaoException {
		if(object == null) {
			return null;
		}
		T entity = asAppengineEntity(object);
		
//		if (!(entity instanceof Website) && entity.getWebsite() == null) {
//			// throw new
//			// DaoException("All entities except websites should have a website parent");
//			entity.setWebsite(new AppengineWebsiteDao().getDefaultWebsite());
//		}
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction txn = datastore.beginTransaction();
		T persistent = null;
		try {
//			if (entity.getKey() == null) {
//				Key websiteKey = (entity.getWebsite() != null) ? entity.getWebsite().getKey()
//						: null;
//				Key entityKey = datastore
//						.allocateIds(websiteKey, entity.getClass().getSimpleName(), 1).iterator()
//						.next();
//				entity.setKey(entityKey);
//				logger.debug("Allocated key {}", entityKey.toString());
//			}
			persistent = pm.makePersistent(entity);
			txn.commit();
			logger.debug("Persisted {}, key: {}, version {}", entity.getClass()
					.getSimpleName(), ((T) persistent).getKey(), ((T) persistent).getVersion());
		} catch (Exception e) {
			logger.error("Not persisted "+entity.getClass().getSimpleName()+", key: "+((T) entity).getKey()+", version "
					+((T) entity).getKey(), ((T) entity).getVersion()+"", e);
			throw new DaoException(e);
		} finally {
			if (txn.isActive()) {
				txn.rollback();
			}
			pm.close();
		}
		return (I) persistent;
	}

	@Override
	public void delete(I entity) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.deletePersistent(entity);
		pm.close();
	}

	
//	public void prepare(EntityBase entity) throws DaoException {
//		if (!(entity instanceof Website) && entity.getWebsite() == null) {
//			// throw new
//			// DaoException("All entities except websites should have a website parent");
//			entity.setWebsite(new AppengineWebsiteDao().getDefaultWebsite());
//		}
//		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
//		if (entity.getKey() == null) {
//			Key websiteKey = (entity.getWebsite() != null) ? entity.getWebsite().getKey()
//					: null;
//			Key entityKey = datastore
//					.allocateIds(websiteKey, entity.getClass().getSimpleName(), 1).iterator()
//					.next();
//			entity.setKey(entityKey);
//			logger.debug("Allocated key {}", entityKey.toString());
//		}
//	}

	protected T asAppengineEntity(I entity) throws DaoException {
		if(entityClass.isInstance(entity)) {
			return (T) entity;
		}
			
		throw new DaoException("Not and instance");
	}

	
	protected AppengineWebsite checkWebsite(Website website) throws DaoException {
		if(!(website instanceof AppengineWebsite)) {
			throw new DaoException("Website is not an instance of AppengineWebsite");
		}
		AppengineWebsite appengineWebsite = (AppengineWebsite) website;
		if(appengineWebsite.getKey() == null) {
			throw new DaoException("Website is not persisted, key is null");
		}
		return appengineWebsite;
	}

}
